#pragma once
#include "cgzITask.h"

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/builder/stream/array.hpp>
#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/builder/basic/array.hpp>
#include <bsoncxx/exception/exception.hpp>
#include <bsoncxx/types.hpp>

enum class cgzCMongoCmd
{
    NONE,       // 无命令
    AUTH,       // 认证
    INSERT,     // 插入
    INSERTS,    // 多条插入
    UPDATE,     // 更新
    DELETE,     // 删除
    DELETE_ONE, // 删除
    COUNT,      // 计数
    FIND,       // 查找
    FIND_ONE,   // 查找一条
    AGGREGATE,  // 聚合
    DISTINCT,   // 去重
};

class cgzCMongoReply : public cgzIData
{
public:
    friend class cgzCHMongo;
    cgzCMongoReply(cgzCMongoCmd code, long cookid);
    virtual ~cgzCMongoReply();

public:
    cgzCMongoCmd m_cmd;
    bool m_err;
    long m_cookid;
    long m_delete;      //删除数量
    std::string m_id;   // 插入标识
};

class cgzCMongoExec : public cgzCMongoReply
{
public:
    friend class cgzCHMongo;
    cgzCMongoExec(const cgzCMongoCmd cmd, const char *collection, bsoncxx::builder::stream::document &doc, const int cookid = -1);
    cgzCMongoExec(const cgzCMongoCmd cmd, const char *collection, std::vector<bsoncxx::document::value> &docs, const int cookid = -1);
    virtual ~cgzCMongoExec();

public:
    std::string m_collection;
    bsoncxx::builder::stream::document m_doc;       // 单挑插入
    std::vector<bsoncxx::document::value> m_docs;   // 多条插入
    // 回复参数
    bool m_ret;
};

class cgzCMongoResult : public cgzCMongoReply
{
public:
    friend class cgzCHMongo;
    cgzCMongoResult(const cgzCMongoCmd cmd, const int cookid, bsoncxx::document::value &result);
    virtual ~cgzCMongoResult();

public:
    bsoncxx::document::value m_result;
};

class cgzCMongoResultMany : public cgzCMongoReply
{
public:
    friend class cgzCHMongo;
    cgzCMongoResultMany(const cgzCMongoCmd cmd, const int cookid);
    virtual ~cgzCMongoResultMany();

public:
    std::vector<bsoncxx::document::value> m_result;
};

class cgzCMongo : public cgzITask
{
public:
    cgzCMongo(
        cgzCThreadPool *pool,
        const char *name,
        const char *ip,
        const char *use,
        const char *password,
        const int port,
        const char *db,
        const int cid);
    virtual ~cgzCMongo();

public:
    bool run(int64_t nms) override;

public:
    bool connect();
    bool rconnect();
    void authret();
    void todoret(cgzCMongoReply *result);

private:
    void add(cgzCMongoExec *exec);
    void del(cgzCMongoExec *exec);
    void get(cgzCMongoExec *exec);
    void set(cgzCMongoExec *exec);
    void num(cgzCMongoExec *exec);
    void agg(cgzCMongoExec *exec);
    void adds(cgzCMongoExec *exec);
    void dels(cgzCMongoExec *exec);
    void gets(cgzCMongoExec *exec);
    void none(cgzCMongoExec *exec);

protected:
    std::string m_ip;
    std::string m_user;
    std::string m_password;
    std::string m_db;
    bool m_firstAuth;
    bool m_ping;
    int m_port;
    int m_cid;
    int m_fd;

private:
    mongocxx::client *m_Mongo;
};
